package com.cnn.servlet;

import anno.CnnInjectService;
import com.cnn.beans.BeanFactory;
import com.cnn.beans.ModelAndView;
import com.cnn.util.PropertiesUtil;
import org.apache.velocity.Template;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;

/**
 * @author Administrator
 * @since 1.0
 */
/*提供一个 servlet类, 该servlet拦截所有请求. 且能满足

        请求 http://localhost/com/cnn/controller/className/method 时,
        com.cnn.controller.className.method
        会调用 'com.cnn.controller.className' 的method
        该method无入参. 页面显示当前服务器的时间毫秒数*/
public class DispatcherServlet extends HttpServlet {

    protected final Logger logger = LoggerFactory.getLogger(this.getClass());
    private Map<String, Object> map = new HashMap<String, Object>();

    private VelocityEngine ve = null;
    private Template t = null;
    @Override
    public void init() {
        Properties properties = PropertiesUtil.loadProperties();
        //map填充key和和对应类的实例，这样不用在访问的时候再找了
        Enumeration enu2 = properties.propertyNames();
        while (enu2.hasMoreElements()) {
            String key = (String) enu2.nextElement();
            try {
                map.put(key, Class.forName(properties.getProperty(key)).newInstance());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        System.out.println("调用ini方法============================" + System.currentTimeMillis());

        //在初始化的时候就要将属性注入到controller
        //遍历集合
        Set<Map.Entry<String, Object>> entries = map.entrySet();
        Object invoke = null;
        for (Map.Entry<String, Object> entry : entries) {
            Class<?> vClass = entry.getValue().getClass();
            try {
                invoke = BeanFactory.getBeanInstance(vClass);
            } catch (Exception e) {
                e.printStackTrace();
            }
            boolean flag = false;
            //获取该类中所有的属性
            Field[] fields = vClass.getDeclaredFields();
            Object field = null;
            try {
                for (Field f : fields) {
                    CnnInjectService cnnInjectServiceAnno = f.getAnnotation(CnnInjectService.class);
                    flag = true;
                    if (flag) {
                        //获取该属性类型的类
                        Class<?> fieldTypeClazz = f.getType();

                        field = BeanFactory.getBeanInstance(fieldTypeClazz);

                        //将这个属性给invoke对象赋值
                        String name = f.getName();
                        name = name.substring(0, 1).toUpperCase() + name.substring(1);
                        // 将属性的首字符大写，方便构造get，set方法
                        String methodName = "set" + name;
                        f.setAccessible(true);
                        Method setter = vClass.getMethod(methodName, fieldTypeClazz);
                        System.out.println("调用setter方法");
                        setter.invoke(invoke, fieldTypeClazz);
                        break;
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        // 初始化模板引擎
        ve = new VelocityEngine();
        ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
        ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
        ve.init();
        // 获取模板文件
        t = ve.getTemplate("com/velocity/hellovelocity.vm");


        ModelAndView mv = null;


    }

    public DispatcherServlet() {
        System.out.println("servlet初始化" + System.currentTimeMillis());
        //new Exception("出错了============================================"+System.currentTimeMillis());
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //test(req, resp);
        test2(req, resp);
    }

    /**
     * 直接通过路径访问
     *
     * @param req  请求
     * @param resp 响应
     * @throws IOException 输入输出异常
     */

    private void test(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        resp.setCharacterEncoding("UTF-8");
        req.setCharacterEncoding("UTF-8");
        resp.setContentType("application/json;charset=utf-8");
        //获取请求的全路径
        String requestURI = req.getRequestURI();
        //对该全路径名进行处理
        requestURI = requestURI.replaceAll("/", ".");
        int n = requestURI.lastIndexOf(".");
        String pathName = requestURI.substring(1, n);
        String method = requestURI.substring(n + 1);
        Object invoke = null;
        try {
            Class<?> clazz = Class.forName(pathName);
            Object o;
            Method[] declaredMethods = clazz.getDeclaredMethods();
            for (Method m : declaredMethods) {
                if (method.equals(m.getName())) {
                    try {

                        if (map.get(pathName) != null) {
                            o = map.get(pathName);
                        } else {
                            o = clazz.newInstance();
                            map.put(pathName, o);
                        }
                        invoke = m.invoke(o);
                        break;
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
            if (invoke != null) {
                resp.getWriter().println(String.valueOf(invoke));
            }


        } catch (ClassNotFoundException e) {
            //e.printStackTrace();
        }


    }

    private void test2(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        //获取请求的全路径
        String method = req.getParameter("method");
        String key = req.getRequestURI();
        Object invoke = map.get(key);
        Class clazz = null;
        Object fieldType = null;
        if ("favicon.ico".equals(key)) {
            return;
        }
        if (invoke != null) {
            clazz = invoke.getClass();
            boolean flag = false;
            try {
                Method[] declaredMethods = invoke.getClass().getDeclaredMethods();
                boolean found = false;
                for (Method m : declaredMethods) {
                    if (method.equals(m.getName())) {
                        Object result = m.invoke(invoke);
                        resp.getWriter().println(String.valueOf(result));
                        found = true;
                        break;
                    }
                }
                if (!found) {
                    resp.getWriter().println("NOT_FOUND");
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        }


    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws
            ServletException, IOException {
        test(req, resp);
    }

    private static String replaceFirstCharToUpperCase(String src) {
        Character c = src.charAt(0);
        int i = (int) c;
        if (i >= 97 && i <= 122) {
            i = i - 32;
            c = (char) i;
        }
        return src.replace(src.charAt(0), c);
    }
}
